#pragma once

#include "lockguard.hpp"
#include "thread.hpp"
#include "task.hpp"
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>

namespace zty
{
    const int THREAD_NUM = 3;
    template <class T>
    class thread_pool
    {
        static thread_pool *s_ins;
        int _thread_num;
        std::vector<zty::thread> _threads;
        std::queue<T> _tasks;
        static pthread_mutex_t _mtx;
        pthread_cond_t _cond;
        bool _terminate = false; // 结束标志

        thread_pool(int thread_num = THREAD_NUM)
            : _thread_num(thread_num),
              _threads(_thread_num)
        {
            // pthread_mutex_init(&_mtx, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }

        ~thread_pool()
        {
            _terminate = true;              // 设置结束标志
            pthread_cond_broadcast(&_cond); // 唤醒所有等待条件变量的线程
            for (auto &e : _threads)        // 回收所有子线程
            {
                e.join();
            }
            // pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }

        thread_pool(const thread_pool &other) = delete;

        struct GC
        {
            ~GC()
            {
                if (s_ins != nullptr)
                {
                    delete s_ins;
                    s_ins = nullptr;
                }
            }
        };

    public:
        static thread_pool &GetInstance(int num = THREAD_NUM)
        {
            if (s_ins == nullptr)
            {
                zty::lock_guard lock(_mtx);
                if (s_ins == nullptr)
                {
                    static GC s_gc;
                    s_ins = new thread_pool(num);
                }
            }
            return *s_ins;
        }

        void push(const T &task)
        {
            zty::lock_guard lock(_mtx);
            _tasks.push(task);
            pthread_cond_signal(&_cond);
        }

        bool pop(T &out)
        {
            zty::lock_guard lock(_mtx);
            while (_tasks.empty())
            {
                pthread_cond_wait(&_cond, &_mtx);
                if (_terminate)
                    return false;
            }

            out = _tasks.front();
            _tasks.pop();
            return true;
        }

        void run()
        {
            for (auto &e : _threads)
            {
                e.run(routine, this);
            }
        }

        static void *routine(void *args)
        {
            thread_pool *self = (thread_pool *)args; // self实际就是this指针
            T task;
            while (!self->_terminate)
            {
                bool ret = self->pop(task);
                // if (self->_terminate)
                //     break;
                // printf("[%d] %d%c%d=%d\n", pthread_self() % 10000, task._l, task._op, task._r, task());
                if (ret) // 判断self->pop是否获取到任务了
                {
                    // LogMessage(NORMAL, "[%d] %d%c%d=%d", /
                    // pthread_self() % 10000, task._l, task._op, task._r, task());
                    // sleep(1);
                    task();
                }
            }
            return (void *)0;
        }
    };

    template <class T>
    thread_pool<T> *thread_pool<T>::s_ins = nullptr;
    template <class T>
    pthread_mutex_t thread_pool<T>::_mtx = PTHREAD_MUTEX_INITIALIZER;
    // template <class T>
    // typename thread_pool<T>::GC thread_pool<T>::s_gc;
}
